package com.sunwayworld.basemodule.rm.materialapply.service.impl;

import com.sunwayworld.basemodule.common.constant.LimsConstant;
import com.sunwayworld.basemodule.rm.material.bean.LimsMaterialBean;
import com.sunwayworld.basemodule.rm.material.bean.LimsStandardHistoryBean;
import com.sunwayworld.basemodule.rm.material.bean.LimsStandardInventoryBean;
import com.sunwayworld.basemodule.rm.material.service.LimsMaterialService;
import com.sunwayworld.basemodule.rm.material.service.LimsStandardHistoryService;
import com.sunwayworld.basemodule.rm.material.service.LimsStandardInventoryService;
import com.sunwayworld.basemodule.rm.materialapply.bean.LimsMaterialApplyBean;
import com.sunwayworld.basemodule.rm.materialapply.bean.LimsMaterialOutBean;
import com.sunwayworld.basemodule.rm.materialapply.dao.LimsMaterialApplyDao;
import com.sunwayworld.basemodule.rm.materialapply.service.LimsMaterialApplyService;
import com.sunwayworld.basemodule.rm.materialapply.service.LimsMaterialOutService;
import com.sunwayworld.basemodule.rm.materialsecondarylibrary.bean.LimsMaterialSecondaryHistoryBean;
import com.sunwayworld.basemodule.rm.materialsecondarylibrary.bean.LimsMaterialSecondaryInventoryBean;
import com.sunwayworld.basemodule.rm.materialsecondarylibrary.bean.LimsMaterialSecondaryLibraryBean;
import com.sunwayworld.basemodule.rm.materialsecondarylibrary.service.LimsMaterialSecondaryHistoryService;
import com.sunwayworld.basemodule.rm.materialsecondarylibrary.service.LimsMaterialSecondaryInventoryService;
import com.sunwayworld.basemodule.rm.materialsecondarylibrary.service.LimsMaterialSecondaryLibraryService;
import com.sunwayworld.basemodule.samplemanage.samplehandle.bean.LimsSampleHandleBean;
import com.sunwayworld.basemodule.samplemanage.samplehandle.service.LimsSampleHandleService;
import com.sunwayworld.framework.at.annotation.AuditTrailEntry;
import com.sunwayworld.framework.at.annotation.AuditTrailType;
import com.sunwayworld.framework.audit.aunnotation.Audit;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.context.LocalContextHelper;
import com.sunwayworld.framework.exception.InvalidDataException;
import com.sunwayworld.framework.i18n.I18nHelper;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.spring.annotation.GikamBean;
import com.sunwayworld.framework.support.auditable.bean.CoreBpmnParameterDTO;
import com.sunwayworld.framework.utils.CollectionUtils;
import com.sunwayworld.framework.utils.ObjectUtils;
import com.sunwayworld.framework.utils.StringUtils;
import com.sunwayworld.module.sys.bpmn.bean.CoreBpmnCommentBean;
import com.sunwayworld.module.sys.bpmn.bean.CoreBpmnInstanceStatusDTO;
import com.sunwayworld.module.sys.bpmn.diagram.ProcessStatus;
import com.sunwayworld.module.sys.bpmn.engine.CoreBpmnRuntimeService;
import com.sunwayworld.module.sys.bpmn.engine.CoreBpmnRuntimeSource;
import com.sunwayworld.module.sys.bpmn.service.CoreBpmnCommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@Repository
@GikamBean
public class LimsMaterialApplyServiceImpl implements LimsMaterialApplyService {

    @Autowired
    private LimsMaterialApplyDao limsMaterialApplyDao;

    @Autowired
    @Lazy
    private LimsMaterialService limsMaterialService;

    @Autowired
    @Lazy
    private LimsStandardInventoryService limsStandardInventoryService;

    @Autowired
    @Lazy
    private LimsStandardHistoryService limsStandardHistoryService;

    @Autowired
    @Lazy
    private LimsMaterialOutService limsMaterialOutService;

    @Autowired
    @Lazy
    private CoreBpmnCommentService coreBpmnCommentService;

    @Autowired
    @Lazy
    private LimsMaterialSecondaryLibraryService limsMaterialSecondaryLibraryService;

    @Autowired
    @Lazy
    private LimsMaterialSecondaryHistoryService limsMaterialSecondaryHistoryService;

    @Autowired
    @Lazy
    private LimsMaterialSecondaryInventoryService limsMaterialSecondaryInventoryService;

    @Override
    @SuppressWarnings("unchecked")
    public LimsMaterialApplyDao getDao() {
        return limsMaterialApplyDao;
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public Long insert(RestJsonWrapperBean jsonWrapper) {
        LimsMaterialApplyBean limsMaterialApply = jsonWrapper.parseUnique(LimsMaterialApplyBean.class);
        limsMaterialApply.setId(ApplicationContextHelper.getNextIdentity());
        limsMaterialApply.setApplyCode(ApplicationContextHelper.getNextSequence(this.getDao().getTable()));
        getDao().insert(limsMaterialApply);

        CoreBpmnCommentBean commentBean = new CoreBpmnCommentBean();
        commentBean.setId(ApplicationContextHelper.getNextIdentity());
        commentBean.setTargetId(this.getDao().getTable().concat("$").concat(limsMaterialApply.getId().toString()));
        commentBean.setTaskName("新建");
        commentBean.setRoute("新建");
        commentBean.setUserId(LocalContextHelper.getLoginUserId());
        commentBean.setUserName(LocalContextHelper.getLoginUserName());
        coreBpmnCommentService.getDao().insert(commentBean);

        return limsMaterialApply.getId();
    }

    @Transactional
    @AuditTrailEntry(AuditTrailType.PROCESS_START)
    @Audit("AUDIT.PROCESS_START")
    @Override
    public List<CoreBpmnInstanceStatusDTO<Long>> startProcess(RestJsonWrapperBean wrapper) {
        List<LimsMaterialApplyBean> itemList = wrapper.parse(this.getDao().getType());
        if (itemList.isEmpty()) {
            return CollectionUtils.emptyList();
        } else {
            this.checkAndUpdateVersion(itemList);
            CoreBpmnRuntimeService runtimeService = ApplicationContextHelper.getBean(CoreBpmnRuntimeService.class);
            List<Long> itemIdList = itemList.stream().map(LimsMaterialApplyBean::getId).collect(Collectors.toList());

            List<LimsMaterialApplyBean> items = this.selectListByFilter(SearchFilter.instance().match("id", itemIdList).filter(MatchPattern.OR));
            List<LimsMaterialOutBean> outBeans = limsMaterialOutService.selectListByFilter(SearchFilter.instance().match("applyId", itemIdList).filter(MatchPattern.OR));
            items.forEach(i -> {
                List<LimsMaterialOutBean> outs = outBeans.stream().filter(o -> o.getApplyId().equals(i.getId())).collect(Collectors.toList());
                if (outs.isEmpty()) {
                    throw new InvalidDataException(i.getApplyCode().concat(" ").concat(I18nHelper.getMessage("BASEMODULE.RM.MATERIALS.TIP.NEED_MATERIAL_OUT")));
                }
                outs.stream().filter(o -> o.getPreOutNum() == null).findAny().ifPresent(o -> {
                    throw new InvalidDataException(i.getApplyCode().concat(": ").concat(o.getMatCode()).concat(" ").concat(I18nHelper.getMessage("BASEMODULE.RM.MATERIALS.TIP.NEED_MATERIAL_OUT_NUM")));
                });
            });

            List<LimsMaterialApplyBean> selectItemList = this.getBpmnVarsItemList(itemIdList);
            List<CoreBpmnRuntimeSource<LimsMaterialApplyBean, Long>> runtimeSourceList = this.parseSubmittableRuntimeSource(itemIdList, CoreBpmnParameterDTO.of(wrapper), this.getBpmnVars(wrapper, selectItemList));
            List<CoreBpmnInstanceStatusDTO<Long>> instanceStatusList = runtimeService.startProcess(runtimeSourceList);
            this.autoPass(runtimeSourceList, instanceStatusList);
            return instanceStatusList;
        }
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.PROCESS_COMPLETE)
    @Audit("AUDIT.PROCESS_COMPLETE")
    public List<CoreBpmnInstanceStatusDTO<Long>> completeTask(RestJsonWrapperBean wrapper) {
        List<LimsMaterialApplyBean> itemList = wrapper.parse(LimsMaterialApplyBean.class);
        if (itemList.isEmpty()) return CollectionUtils.emptyList();
        // 执行工作流
        List<CoreBpmnInstanceStatusDTO<Long>> instanceStatusDTOS = LimsMaterialApplyService.super.completeTask(wrapper);
        // 判断是否是最后一道工作流
        if (!StringUtils.equals(instanceStatusDTOS.get(0).getProcessStatus().name(), ProcessStatus.DONE.name())) {
            return instanceStatusDTOS;
        }
        // 执行出库逻辑，先入先出（都是出库扣减数量，不存在退库增加数量）
        List<Long> applyIds = itemList.stream().map(LimsMaterialApplyBean::getId).collect(Collectors.toList());
        List<LimsMaterialApplyBean> materialApplyBeans = selectListByIds(applyIds);
        applyIds = materialApplyBeans.stream().map(LimsMaterialApplyBean::getId).collect(Collectors.toList());
        List<LimsMaterialOutBean> materialOutBeans = limsMaterialOutService.selectListByFilter(SearchFilter.instance().match("applyId", applyIds).filter(MatchPattern.OR));
        if (materialOutBeans.stream().anyMatch(e -> ObjectUtils.isEmpty(e.getOutNum()))) {
            throw new InvalidDataException(I18nHelper.getMessage("BASEMODULE.RM.MATERIALS.TIP.NEED_MATERIAL_OUT"));
        }
        Map<String, List<LimsMaterialOutBean>> materialOutMaps = materialOutBeans.stream().collect(Collectors.groupingBy(LimsMaterialOutBean::getMatCode));

        List<String> matCodes = materialOutBeans.stream().map(LimsMaterialOutBean::getMatCode).distinct().collect(Collectors.toList());
        List<LimsMaterialBean> materialBeans = limsMaterialService.selectListByFilter(SearchFilter.instance().match("matCode", matCodes).filter(MatchPattern.OR));

        // 获取库存大于0且未过期的批次
        List<LimsStandardInventoryBean> inventoryBeanList = limsStandardInventoryService.selectListByFilter(SearchFilter.instance().match("matCode", matCodes).filter(MatchPattern.OR)
                .match("batchNum", 0D).filter(MatchPattern.NG)
                .match("MATEXPIRED", "0").filter(MatchPattern.EQ));
        Map<String, List<LimsStandardInventoryBean>> inventoryMaps = inventoryBeanList.stream().collect(Collectors.groupingBy(LimsStandardInventoryBean::getMatCode));

        List<String> noMatCodes = new ArrayList<>();
        Map<Long, List<LimsMaterialApplyBean>> applyMaps = materialApplyBeans.stream().collect(Collectors.groupingBy(LimsMaterialApplyBean::getId));
        // 先入先出
        List<LimsStandardInventoryBean> updateInventorys = new ArrayList<>();
        List<LimsStandardHistoryBean> standardHistoryBeans = new ArrayList<>();
        double matOutNum;
        double beOutNum;
        double num = 0D;
        LocalDateTime now = LocalDateTime.now();

        // 数据转存到材料二级库相关表（按照出库单+物料维度插入记录）
        List<LimsMaterialSecondaryLibraryBean> insertLibraries = new ArrayList<>();
        List<LimsMaterialSecondaryLibraryBean> updateLibraries = new ArrayList<>();
        List<LimsMaterialSecondaryHistoryBean> insertHistories = new ArrayList<>();

        List<String> groups = materialApplyBeans.stream().map(LimsMaterialApplyBean::getGroupType).distinct().collect(Collectors.toList());
        List<Long> matIds = materialBeans.stream().map(LimsMaterialBean::getId).collect(Collectors.toList());
        List<LimsMaterialSecondaryLibraryBean> existLibraries = limsMaterialSecondaryLibraryService.selectListByFilter(SearchFilter.instance().match("groupType", groups).filter(MatchPattern.OR).match("matId", matIds).filter(MatchPattern.OR));

        for (LimsMaterialBean materialBean : materialBeans) {
            matOutNum = 0D;

            List<LimsMaterialOutBean> outBeans = materialOutMaps.get(materialBean.getMatCode());
            if (!inventoryMaps.containsKey(materialBean.getMatCode())) {
                noMatCodes.add(materialBean.getMatCode());
                break;
            }
            List<LimsStandardInventoryBean> inventoryBeans = inventoryMaps.get(materialBean.getMatCode());
            // 校验库存数量是否足够（不能直接跟总库存比较）
            double outSum = outBeans.stream().mapToDouble(LimsMaterialOutBean::getOutNum).sum();
            double inventorySum = inventoryBeans.stream().mapToDouble(LimsStandardInventoryBean::getBatchNum).sum();
            if (inventorySum < outSum) {
                noMatCodes.add(materialBean.getMatCode());
                break;
            }

            inventoryBeans.sort(Comparator.comparing(LimsStandardInventoryBean::getOperateTime));
            for (LimsMaterialOutBean outBean : outBeans) {
                beOutNum = 0D;
                LimsMaterialApplyBean applyBean = applyMaps.get(outBean.getApplyId()).get(0);
                for (LimsStandardInventoryBean inventoryBean : inventoryBeans) {
                    if (beOutNum >= outBean.getOutNum()) break;
                    if (inventoryBean.getBatchNum() <= 0D) continue;
                    
                    if (beOutNum+inventoryBean.getBatchNum() < outBean.getOutNum()) {
                        num = inventoryBean.getBatchNum();
                        beOutNum = beOutNum + inventoryBean.getBatchNum();
                        inventoryBean.setBatchNum(0D);
                    } else if (beOutNum+inventoryBean.getBatchNum() >= outBean.getOutNum()) {
                        num = outBean.getOutNum()-beOutNum;// 需要出库的数量
                        beOutNum = outBean.getOutNum();
                        inventoryBean.setBatchNum(inventoryBean.getBatchNum()-num);
                    }
                    updateInventorys.add(inventoryBean);
                    // 添加操作记录
                    LimsStandardHistoryBean standardHistoryBean = limsStandardInventoryService.getHistory(inventoryBean, num, inventoryBean.getSupplier(), LimsConstant.MATERIAL_OPERATION_TAKE);
                    standardHistoryBean.setApplyId(outBean.getApplyId());
                    standardHistoryBean.setStandardInventoryId(inventoryBean.getId());
                    standardHistoryBean.setIssueType(applyBean.getApplyType());
                    standardHistoryBean.setAuditStatus("完成");
                    standardHistoryBean.setCompleteTime(now);
                    standardHistoryBeans.add(standardHistoryBean);

                    // 校验二级库对应物料是否存在（不存在则插入，存在则更新库存）
                    Optional<LimsMaterialSecondaryLibraryBean> optional = existLibraries.stream().filter(el -> el.getMatCode().equals(inventoryBean.getMatCode()) && el.getGroupType().equals(applyBean.getGroupType())).findAny();
                    // 定一个空的
                    LimsMaterialSecondaryLibraryBean matLibraryBean;
                    if (optional.isPresent()) {
                        Optional<LimsMaterialSecondaryLibraryBean> willUpdate = updateLibraries.stream().filter(il -> il.getMatCode().equals(inventoryBean.getMatCode()) && il.getGroupType().equals(applyBean.getGroupType())).findAny();
                        if (willUpdate.isPresent()) {
                            LimsMaterialSecondaryLibraryBean libraryBean = willUpdate.get();
                            libraryBean.setMatNum(libraryBean.getMatNum() + standardHistoryBean.getQuantity());
                            matLibraryBean = libraryBean;
                        } else {
                            updateLibraries.add(optional.get());
                            LimsMaterialSecondaryLibraryBean libraryBean = optional.get();
                            libraryBean.setMatNum(libraryBean.getMatNum() + standardHistoryBean.getQuantity());
                            matLibraryBean = libraryBean;
                        }
                    } else {
                        Optional<LimsMaterialSecondaryLibraryBean> willInsert = insertLibraries.stream().filter(il -> il.getMatCode().equals(inventoryBean.getMatCode()) && il.getGroupType().equals(applyBean.getGroupType())).findAny();
                        if (willInsert.isPresent()) {
                            LimsMaterialSecondaryLibraryBean libraryBean = willInsert.get();
                            libraryBean.setMatNum(libraryBean.getMatNum() + standardHistoryBean.getQuantity());
                            matLibraryBean = libraryBean;
                        } else {
                            LimsMaterialSecondaryLibraryBean libraryBean = new LimsMaterialSecondaryLibraryBean();
                            insertLibraries.add(libraryBean);
                            libraryBean.setMatNum(0D);
                            libraryBean.setMatNum(libraryBean.getMatNum() + standardHistoryBean.getQuantity());
                            libraryBean.setId(ApplicationContextHelper.getNextIdentity());
                            libraryBean.setGroupType(applyBean.getGroupType());
                            libraryBean.setMatCode(inventoryBean.getMatCode());
                            materialBeans.stream().filter(m -> m.getMatCode().equals(inventoryBean.getMatCode())).findAny().ifPresent(m -> {
                                libraryBean.setMatId(m.getId());
                                libraryBean.setStorageLocation(m.getStorageLocation());
                                libraryBean.setMatName(m.getMatName());
                            });
                            matLibraryBean = libraryBean;
                        }
                    }

                    LimsMaterialSecondaryLibraryBean finalMatLibraryBean = matLibraryBean;
                    Optional<LimsMaterialSecondaryHistoryBean> willInsertHistory = insertHistories.stream().filter(ii -> ii.getMatSecondId().equals(finalMatLibraryBean.getId()) && ii.getApplyId().equals(applyBean.getId())).findAny();
                    if (willInsertHistory.isPresent()) {
                        LimsMaterialSecondaryHistoryBean insertHistory = willInsertHistory.get();
                        insertHistory.setQuantity(insertHistory.getQuantity() + standardHistoryBean.getQuantity());
                    } else {
                        LimsMaterialSecondaryHistoryBean insertHistory = new LimsMaterialSecondaryHistoryBean();
                        insertHistories.add(insertHistory);

                        insertHistory.setId(ApplicationContextHelper.getNextIdentity());
                        insertHistory.setMatSecondId(finalMatLibraryBean.getId());
                        insertHistory.setStatus("完成");
                        insertHistory.setQuantity(standardHistoryBean.getQuantity());
                        insertHistory.setCompleteTime(now);
                        insertHistory.setIssueType("");
                        insertHistory.setOperation(LimsConstant.MATERIAL_OPERATION_ADD);
                        insertHistory.setApplyId(applyBean.getId());
                    }
                }
                matOutNum = matOutNum + outBean.getOutNum();
            }
            materialBean.setMatNum(materialBean.getMatNum() - matOutNum);
        }
        if (!noMatCodes.isEmpty()) {
            throw new InvalidDataException("以下物料【"+StringUtils.join(noMatCodes, ",")+"】不存在或未过期库存不足！");
        }
        // 生成二级库存记录表
        if (!insertLibraries.isEmpty()) {
            limsMaterialSecondaryLibraryService.getDao().insert(insertLibraries);
        }
        if (!updateLibraries.isEmpty()) {
            limsMaterialSecondaryLibraryService.getDao().update(updateLibraries, "matNum");
        }
        if (!insertHistories.isEmpty()) {
            limsMaterialSecondaryHistoryService.getDao().insert(insertHistories);
        }
        // 更新库存
        limsStandardHistoryService.getDao().insert(standardHistoryBeans);
        limsStandardInventoryService.getDao().update(updateInventorys, "batchNum");
        limsMaterialService.getDao().update(materialBeans, "matNum");

        return instanceStatusDTOS;
    }
    // old code
    /*public List<CoreBpmnInstanceStatusDTO<Long>> completeTask(RestJsonWrapperBean wrapper) {
        List<LimsMaterialApplyBean> itemList = wrapper.parse(LimsMaterialApplyBean.class);
        List<LimsMaterialApplyBean> materialApplyBeans = selectListByIds(itemList.stream().map(LimsMaterialApplyBean::getId).collect(Collectors.toList()));
        List<Long> applyIds = materialApplyBeans.stream().map(LimsMaterialApplyBean::getId).collect(Collectors.toList());
        List<LimsMaterialOutBean> materialOutBeans = limsMaterialOutService.selectListByFilter(SearchFilter.instance().match("applyId", applyIds).filter(MatchPattern.OR));
        // 校验出库数量
        String message = materialOutBeans.stream().filter(e -> e.getPreOutNum() == null || e.getPreOutNum() == 0D).map(e -> e.getBatchNo() + "-" + e.getMatCode()).distinct().collect(Collectors.joining("<br/>"));
        if (!StringUtils.isEmpty(message)) {
            throw new InvalidDataException(message + I18nHelper.getMessage("BASEMODULE.RM.MATERIALS.TIP.OUTNUM_IS_ZERO"));
        }
        List<String> matCodes = materialOutBeans.stream().map(LimsMaterialOutBean::getMatCode).distinct().collect(Collectors.toList());
        List<LimsMaterialBean> materialBeans = limsMaterialService.selectListByFilter(SearchFilter.instance().match("matCode", matCodes).filter(MatchPattern.OR));
        List<Long> matIds = materialBeans.stream().map(LimsMaterialBean::getId).collect(Collectors.toList());
        List<LimsStandardHistoryBean> standardHistoryBeans = limsStandardHistoryService.selectListByFilter(SearchFilter.instance().match("applyId", applyIds).filter(MatchPattern.OR));
        List<Long> inventoryIds = standardHistoryBeans.stream().map(LimsStandardHistoryBean::getStandardInventoryId).distinct().collect(Collectors.toList());
        List<LimsStandardInventoryBean> standardInventoryBeans = limsStandardInventoryService.selectListByFilter(SearchFilter.instance().match("id", inventoryIds).filter(MatchPattern.OR));
        List<LimsStandardInventoryBean> inventoryBeansAll = limsStandardInventoryService.selectListByFilter(SearchFilter.instance().match("matCode", matCodes).filter(MatchPattern.OR));

        StringBuffer bf = new StringBuffer();
        materialOutBeans.forEach(mo -> {
            AtomicBoolean flag = new AtomicBoolean(false);
            List<LimsStandardInventoryBean> si = inventoryBeansAll.stream().filter(s -> s.getMatCode().equals(mo.getMatCode())).collect(Collectors.toList());
            si.forEach(i -> {
                Optional<LimsStandardHistoryBean> oh = standardHistoryBeans.stream().filter(h -> h.getStandardInventoryId().equals(i.getId()) && h.getApplyId().equals(mo.getApplyId())).findAny();
                if (oh.isPresent()) {
                    flag.getAndSet(true);
                }
            });
            if (!flag.get()) {
                bf.append(mo.getBatchNo()).append("-").append(mo.getMatCode()).append("<br/>");
            }
        });
        if (bf.length() > 0) {
            throw new InvalidDataException(bf + I18nHelper.getMessage("BASEMODULE.RM.MATERIALS.TIP.OUTNUM_IS_ZERO"));
        }

        // 数据转存到材料二级库相关表
        List<LimsMaterialSecondaryLibraryBean> insertLibraries = new ArrayList<>();
        List<LimsMaterialSecondaryLibraryBean> updateLibraries = new ArrayList<>();
        List<LimsMaterialSecondaryInventoryBean> insertInventories = new ArrayList<>();
        List<LimsMaterialSecondaryHistoryBean> insertHistories = new ArrayList<>();

        List<String> groups = materialApplyBeans.stream().map(LimsMaterialApplyBean::getGroupType).distinct().collect(Collectors.toList());
        List<LimsMaterialSecondaryLibraryBean> existLibraries = limsMaterialSecondaryLibraryService.selectListByFilter(SearchFilter.instance().match("groupType", groups).filter(MatchPattern.OR).match("matId", matIds).filter(MatchPattern.OR));

        LocalDateTime time = LocalDateTime.now();
        // 计算出库
//        calcOut(materialApplyBeans, materialBeans, standardHistoryBeans, standardInventoryBeans, time);
        for (LimsStandardInventoryBean ms : standardInventoryBeans) {
            double sum = 0D;// 增加的库存+扣减的库存
            double oldInvNum = ms.getBatchNum() == null ? 0D : ms.getBatchNum();
            List<LimsStandardHistoryBean> collect = standardHistoryBeans.stream().filter(sh -> sh.getStandardInventoryId().equals(ms.getId())).collect(Collectors.toList());
            for (LimsStandardHistoryBean s : collect) {
                Optional<LimsMaterialApplyBean> optionalMaterialApplyBean = materialApplyBeans.stream().filter(e -> e.getId().equals(s.getApplyId())).findFirst();
                if (!optionalMaterialApplyBean.isPresent()) continue;
                LimsMaterialApplyBean materialApplyBean = optionalMaterialApplyBean.get();
                if (!StringUtils.equals(materialApplyBean.getApplyType(), "sctk")) {
                    // 计算差值
                    ms.setBatchNum(ms.getBatchNum() - s.getQuantity());
                    sum -= s.getQuantity();
                } else {
                    ms.setBatchNum(ms.getBatchNum() + s.getQuantity());// 生产退库增加库存
                    sum += s.getQuantity();
                }
                s.setAuditStatus("完成");
                s.setCompleteTime(time);

                Optional<LimsMaterialSecondaryLibraryBean> optional = existLibraries.stream().filter(el -> el.getMatCode().equals(ms.getMatCode()) && el.getGroupType().equals(materialApplyBean.getGroupType())).findAny();

                // 定一个空的
                LimsMaterialSecondaryLibraryBean matLibraryBean;
                if (optional.isPresent()) {
                    Optional<LimsMaterialSecondaryLibraryBean> willUpdate = updateLibraries.stream().filter(il -> il.getMatCode().equals(ms.getMatCode()) && il.getGroupType().equals(materialApplyBean.getGroupType())).findAny();
                    if (willUpdate.isPresent()) {
                        LimsMaterialSecondaryLibraryBean libraryBean = willUpdate.get();
                        // 出库对应二级库应该是增加库存
                        // 生产退库对应二级库应该是减少库存?
                        if (!StringUtils.equals(materialApplyBean.getApplyType(), "sctk")) {
                            libraryBean.setMatNum(libraryBean.getMatNum() + s.getQuantity());
                        } else {
                            libraryBean.setMatNum(libraryBean.getMatNum() - s.getQuantity());
                        }
                        matLibraryBean = libraryBean;
                    } else {
                        updateLibraries.add(optional.get());
                        LimsMaterialSecondaryLibraryBean libraryBean = optional.get();
                        // 出库对应二级库应该是增加库存
                        // 生产退库对应二级库应该是减少库存?
                        if (!StringUtils.equals(materialApplyBean.getApplyType(), "sctk")) {
                            libraryBean.setMatNum(libraryBean.getMatNum() + s.getQuantity());
                        } else {
                            libraryBean.setMatNum(libraryBean.getMatNum() - s.getQuantity());
                        }
                        matLibraryBean = libraryBean;
                    }
                } else {
                    Optional<LimsMaterialSecondaryLibraryBean> willInsert = insertLibraries.stream().filter(il -> il.getMatCode().equals(ms.getMatCode()) && il.getGroupType().equals(materialApplyBean.getGroupType())).findAny();
                    if (willInsert.isPresent()) {
                        LimsMaterialSecondaryLibraryBean libraryBean = willInsert.get();
                        // 出库对应二级库应该是增加库存
                        // 生产退库对应二级库应该是减少库存?
                        if (!StringUtils.equals(materialApplyBean.getApplyType(), "sctk")) {
                            libraryBean.setMatNum(libraryBean.getMatNum() + s.getQuantity());
                        } else {
                            libraryBean.setMatNum(libraryBean.getMatNum() - s.getQuantity());
                        }
                        matLibraryBean = libraryBean;
                    } else {
                        LimsMaterialSecondaryLibraryBean libraryBean = new LimsMaterialSecondaryLibraryBean();
                        insertLibraries.add(libraryBean);
                        libraryBean.setMatNum(0D);
                        // 出库对应二级库应该是增加库存
                        // 生产退库对应二级库应该是减少库存?
                        if (!StringUtils.equals(materialApplyBean.getApplyType(), "sctk")) {
                            libraryBean.setMatNum(libraryBean.getMatNum() + s.getQuantity());
                        } else {
                            libraryBean.setMatNum(libraryBean.getMatNum() - s.getQuantity());
                        }
                        libraryBean.setId(ApplicationContextHelper.getNextIdentity());
                        libraryBean.setGroupType(materialApplyBean.getGroupType());
                        libraryBean.setMatCode(ms.getMatCode());
                        materialBeans.stream().filter(m -> m.getMatCode().equals(ms.getMatCode())).findAny().ifPresent(m -> {
                            libraryBean.setMatId(m.getId());
                            libraryBean.setStorageLocation(m.getStorageLocation());
                            libraryBean.setMatName(m.getMatName());
                        });
                        matLibraryBean = libraryBean;
                    }
                }

                LimsMaterialSecondaryLibraryBean finalMatLibraryBean = matLibraryBean;
                Optional<LimsMaterialSecondaryInventoryBean> willInsertInventory = insertInventories.stream().filter(ii -> ii.getMatSecondId().equals(finalMatLibraryBean.getId()) && ii.getInventoryId().equals(ms.getId())).findAny();
                if (willInsertInventory.isPresent()) {
                    LimsMaterialSecondaryInventoryBean insertInventory = willInsertInventory.get();
                    // 出库对应二级库应该是增加库存
                    // 生产退库对应二级库应该是减少库存?
                    if (!StringUtils.equals(materialApplyBean.getApplyType(), "sctk")) {
                        insertInventory.setBatchNum(insertInventory.getBatchNum() + s.getQuantity());
                    } else {
                        insertInventory.setBatchNum(insertInventory.getBatchNum() - s.getQuantity());
                    }
                    insertInventory.setStorageNum(insertInventory.getBatchNum());
                } else {
                    LimsMaterialSecondaryInventoryBean insertInventory = new LimsMaterialSecondaryInventoryBean();
                    insertInventories.add(insertInventory);

                    insertInventory.setId(ApplicationContextHelper.getNextIdentity());
                    insertInventory.setMatSecondId(matLibraryBean.getId());
                    insertInventory.setInventoryId(ms.getId());
                    insertInventory.setMatId(matLibraryBean.getMatId());
                    insertInventory.setMatCode(matLibraryBean.getMatCode());
                    insertInventory.setOperateTime(time);
                    insertInventory.setUsefulTime(ms.getUsefulTime());
                    insertInventory.setWarrantyExpiryDate(ms.getWarrantyExpiryDate());
                    insertInventory.setBatchNum(0D);
                    if (!StringUtils.equals(materialApplyBean.getApplyType(), "sctk")) {
                        // 出库对应二级库应该是增加库存
                        insertInventory.setBatchNum(insertInventory.getBatchNum() + s.getQuantity());
                    } else {
                        insertInventory.setBatchNum(insertInventory.getBatchNum() - s.getQuantity());
                        // 生产退库对应二级库应该是减少库存?
                    }
                    insertInventory.setStorageNum(insertInventory.getBatchNum());
                }
            }
            Optional<LimsMaterialBean> optionalMaterialBean = materialBeans.stream().filter(e -> StringUtils.equals(e.getMatCode(), ms.getMatCode())).findFirst();
            if (ms.getBatchNum() < 0) {
                if (optionalMaterialBean.isPresent()) {
                    throw new InvalidDataException("材料：".concat(optionalMaterialBean.get().getMatCode()).concat(" 的批次：").concat(ms.getStorageBatch()).concat("出库数量超过批次剩余量！"));
                } else {
                    throw new InvalidDataException("批次：".concat(ms.getStorageBatch()).concat("出库数量超过批次剩余量！"));
                }
            }
            // 计算最终的批次库存数
            if (optionalMaterialBean.isPresent()) {
                LimsMaterialBean materialBean = optionalMaterialBean.get();
                materialBean.setMatNum(materialBean.getMatNum() + sum);
            }
        }

        // 生成二级库存记录表
        insertInventories.forEach(ii -> {
            LimsMaterialSecondaryHistoryBean historyBean = new LimsMaterialSecondaryHistoryBean();
            insertHistories.add(historyBean);

            historyBean.setId(ApplicationContextHelper.getNextIdentity());
            historyBean.setSecondInventoryId(ii.getId());
            historyBean.setStatus("完成");
            historyBean.setQuantity(ii.getBatchNum());
            historyBean.setCompleteTime(time);
            historyBean.setIssueType("");
            historyBean.setOperation(LimsConstant.MATERIAL_OPERATION_ADD);
        });

        if (!insertLibraries.isEmpty()) {
            limsMaterialSecondaryLibraryService.getDao().insert(insertLibraries);
        }
        if (!updateLibraries.isEmpty()) {
            limsMaterialSecondaryLibraryService.getDao().update(updateLibraries, "matNum");
        }
        if (!insertInventories.isEmpty()) {
            limsMaterialSecondaryInventoryService.getDao().insert(insertInventories);
        }
        if (!insertHistories.isEmpty()) {
            limsMaterialSecondaryHistoryService.getDao().insert(insertHistories);
        }

        limsStandardHistoryService.getDao().update(standardHistoryBeans, "auditStatus", "completeTime");
        limsMaterialService.getDao().update(materialBeans, "matNum");
        limsStandardInventoryService.getDao().update(standardInventoryBeans, "batchNum");
        // 更新已出库数量
        materialOutBeans.forEach(m -> m.setOutNum(m.getPreOutNum()));
        limsMaterialOutService.getDao().update(materialOutBeans, "outNum");
        CoreBpmnRuntimeService runtimeService = ApplicationContextHelper.getBean(CoreBpmnRuntimeService.class);
        List<CoreBpmnRuntimeSource<LimsMaterialApplyBean, Long>> runtimeSourceList = parseSubmittableRuntimeSource((List) materialApplyBeans.stream().map((i) -> i.getId()).collect(Collectors.toList()), CoreBpmnParameterDTO.of(wrapper), this.getBpmnVars(wrapper, materialApplyBeans));
        List<CoreBpmnInstanceStatusDTO<Long>> instanceStatusList = runtimeService.completeTask(runtimeSourceList);
        return instanceStatusList;
    }*/

    private void calcOut(List<LimsMaterialApplyBean> materialApplyBeans, List<LimsMaterialBean> materialBeans, List<LimsStandardHistoryBean> standardHistoryBeans, List<LimsStandardInventoryBean> standardInventoryBeans, LocalDateTime time) {
        // 多个申请单出库类型不一样，一个入库单既可能扣减内存，有可能增加库存，需要综合考虑（当前数量+增加库存是否满足扣减库存）
        for (LimsStandardInventoryBean ms : standardInventoryBeans) {
            double sum = 0;// 增加的库存+扣减的库存
            List<LimsStandardHistoryBean> collect = standardHistoryBeans.stream().filter(sh -> sh.getStandardInventoryId().equals(ms.getId())).collect(Collectors.toList());
            for (LimsStandardHistoryBean s : collect) {
                Optional<LimsMaterialApplyBean> optionalMaterialApplyBean = materialApplyBeans.stream().filter(e -> e.getId().equals(s.getApplyId())).findFirst();
                if (!optionalMaterialApplyBean.isPresent()) continue;
                LimsMaterialApplyBean materialApplyBean = optionalMaterialApplyBean.get();
                if (!StringUtils.equals(materialApplyBean.getApplyType(), "sctk")) {
                    // 计算差值
                    ms.setBatchNum(ms.getBatchNum() - s.getQuantity());
                    sum -= s.getQuantity();
                } else {
                    ms.setBatchNum(ms.getBatchNum() + s.getQuantity());// 生产退库增加库存
                    sum += s.getQuantity();
                }
                s.setAuditStatus("完成");
                s.setCompleteTime(time);
            }
            // 计算最终的批次库存数
            Optional<LimsMaterialBean> optionalMaterialBean = materialBeans.stream().filter(e -> StringUtils.equals(e.getMatCode(), ms.getMatCode())).findFirst();
            if (optionalMaterialBean.isPresent()) {
                LimsMaterialBean materialBean = optionalMaterialBean.get();
                materialBean.setMatNum(materialBean.getMatNum() + sum);
            }
        }
    }
}
